package cn.shrek.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import cn.shrek.realm.UserRealm;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

@Configuration
@EnableConfigurationProperties(value = {ShiroProperties.class})
public class ShiroAutoConfiguration {

    public static final String SHIRO_FILTER="shiroFilter";


    private ShiroProperties shiroProperties;




    public ShiroAutoConfiguration(ShiroProperties shiroProperties) {
        this.shiroProperties = shiroProperties;
    }


    /**
     * 创建凭证匹配器
     */
    @Bean
    public CredentialsMatcher credentialsMatcher(){
        HashedCredentialsMatcher credentialsMatcher=new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName(shiroProperties.getHashAlgorithmName());
        credentialsMatcher.setHashIterations(shiroProperties.getHashIterations());
        return credentialsMatcher;
    }

    /**
     * 创建realm
     */
    @Bean
    public UserRealm userRealm(CredentialsMatcher credentialsMatcher){
        UserRealm userRealm=new UserRealm();
        //注入凭证匹配器
        userRealm.setCredentialsMatcher(credentialsMatcher);
        return userRealm;
    }

    /**
     * 创建安全管理器
     */
    @Bean
    public SecurityManager defaultWebSecurityManager(UserRealm userRealm){
        DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
        //注入realm
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    /**
     * 创建shiroFilter
     */
    @Bean(value = SHIRO_FILTER)
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
        ShiroFilterFactoryBean filterFactoryBean=new ShiroFilterFactoryBean();
        //注入安全管理器
        filterFactoryBean.setSecurityManager(securityManager);
        //没有登录 访问时返回的页面
        filterFactoryBean.setLoginUrl(shiroProperties.getLoginUrl());
        //设置没有权限时跳转的页面
        filterFactoryBean.setUnauthorizedUrl(shiroProperties.getUnauthorizedUrl());
        //配置shiro的内置的过滤器链
        String[] anonUrl = shiroProperties.getAnonUrl();//直接放行的url
        String[] authcUrl = shiroProperties.getAuthcUrl();//需要认证之后才能访问的url

        Map<String, String> filterChainDefinitionMap=new HashMap<>();
        for (String anon : anonUrl) {
            filterChainDefinitionMap.put(anon,"anon");
        }
        for (String authc : authcUrl) {
            //其它地址 必须认证才能访问
            filterChainDefinitionMap.put(authc,"authc");
        }

        filterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return filterFactoryBean;

    }

    /**
     * 注册filter
     */
    @Bean
    public FilterRegistrationBean<DelegatingFilterProxy> filterProxyFilterRegistrationBean(){
        DelegatingFilterProxy proxy=new DelegatingFilterProxy();
        FilterRegistrationBean<DelegatingFilterProxy> registrationBean=new FilterRegistrationBean<>();
        //设置过滤器
        registrationBean.setFilter(proxy);
        //设置参数
        registrationBean.addInitParameter("targetFilterLifecycle","true");
        registrationBean.addInitParameter("targetBeanName",SHIRO_FILTER);

        //设置拦截路径
        registrationBean.setServletNames(Arrays.asList(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));

        return registrationBean;

    }

    /**
     * 这里是为了能在html页面引用shiro标签，不然不会走授权方法
     */
    @Bean(name = "shiroDialect")
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }

}
